#pragma once

#include <sys/select.h>
#include <string>
#include <iostream>

#include "Sock.hpp"
#include "Log.hpp"

typedef int fd_t;

const static uint16_t DEFAULTPORT = 8888;
const static int N = sizeof(fd_set) * sizeof(__fd_mask);
const static fd_t DEFAULTFD = -1;

class SelectServer
{
public:
    SelectServer(uint16_t port = DEFAULTPORT) : _port(port)
    {
        for (int i = 0; i < N; ++i)
            _fdarray[i] = DEFAULTFD;
    }
    ~SelectServer()
    {
        _listen_sock.Close();
    }
    void InitServer()
    {
        _listen_sock.Socket();
        _listen_sock.Bind(_port);
        _listen_sock.Listen();
    }
    void HandleEvent(fd_set &rfds)
    {
        // 处理监听套接字的就绪事件
        if (FD_ISSET(_listen_sock.Fd(), &rfds))
        {
            std::cout << "有一个新链接到了" << std::endl;
            // 此时，去Accept就不会被阻塞！
            std::string clientip;
            uint16_t clientport;
            int sock = _listen_sock.Accept(&clientip, &clientport);
            logMessage(Debug, "sock: [%s: %d]", clientip.c_str(), clientport);

            // 把新得到的添加进_fdarray管理起来
            int i = 1;
            for (; i < N; ++i)
            {
                if (_fdarray[i] == DEFAULTFD)
                    break;
            }
            if (i >= N)
            {
                // fdarray满了，服务器压力已爆满
                close(sock);
                logMessage(Warning, "sock已满");
            }
            else
            {
                _fdarray[i] = sock;
            }
        }
        // 处理其他sock的就绪事件
        for (int i = 1; i < N; ++i)
        {
            if (_fdarray[i] == DEFAULTFD)
                continue;
            if (FD_ISSET(_fdarray[i], &rfds))
            {
                std::cout << "有数据了！\n";
                // ServiceIO();
                // 此时，去读取，不会被阻塞了！
                char buf[1024];
                ssize_t s = recv(_fdarray[i], buf, sizeof(buf) - 1, 0);
                if (s > 0)
                {
                    buf[s - 1] = '\0';
                    std::cout << "client: " << buf << std::endl;
                    std::string sends = "[from server] ";
                    sends += buf;
                    send(_fdarray[i], sends.c_str(), sends.size(), 0);
                }
                else
                {
                    close(_fdarray[i]);
                    _fdarray[i] = DEFAULTFD;
                }
            }
        }
    }
    void Start()
    {
        // struct timeval timeout = {2, 0};

        _fdarray[0] = _listen_sock.Fd();
        while (true)
        {
            // timeout = {2, 0};
            // int n = select(_listen_sock.Fd() + 1, &rfds, nullptr, nullptr, &timeout);

            fd_set rfds; // 等待读事件的fd
            int maxfd = _fdarray[0];
            FD_ZERO(&rfds);
            for (int i = 0; i < N; ++i)
            {
                if (_fdarray[i] != DEFAULTFD)
                    FD_SET(_fdarray[i], &rfds);
                if(maxfd < _fdarray[i])
                    maxfd = _fdarray[i];
            }

            int n = select(maxfd + 1, &rfds, nullptr, nullptr, nullptr); // 阻塞式等待
            switch (n)
            {
            case 0:
                logMessage(Debug, "Time out, %d: %s", errno, strerror(errno));
                break;
            case -1:
                logMessage(Fatal, "%d: %s", errno, strerror(errno));
                break;
            default:
                logMessage(Debug, "有一个就绪事件发生了: %d", n);
                HandleEvent(rfds);
                DebugPrint();
                break;
            }
            sleep(1);
        }
    }
    void DebugPrint()
    {
        std::cout << "_fdarray[]: ";
        for (int i = 0; i < N; ++i)
            if (_fdarray[i] != DEFAULTFD)
                std::cout << _fdarray[i] << " ";
        std::cout << "\n";
    }

private:
    uint16_t _port;
    Sock _listen_sock;
    fd_t _fdarray[N]; // 保存所有需要select等待的fd
};